import email
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from .board import InitialBoard
from visualization.models import playerLog

battlers=dict()
layouts=dict()

class battleConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        roomname = self.scope['url_route']['kwargs']['roomID']
        try:
            if len(battlers[roomname])>1:
                await self.close()
        except:
            battlers[roomname]=dict()
        
        self.room_name = roomname
        self.room_group_name = 'gobang_%s' % self.room_name

        # Join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        await self.accept()
        battlers[roomname][self.channel_name]=self.send
        layouts[self.room_name]=[]
        for i in InitialBoard:
            layouts[self.room_name].append(list(i))

        # 开整！
        if len(battlers[roomname])>1:
            chess=1
            for _,values in battlers[self.room_name].items():
                await values(
                    text_data=json.dumps(
                        {'type':'start',
                        'data':chess,}
                    )
                )
                chess=-chess

    async def disconnect(self, close_code):
        # Leave room group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

        battlers[self.room_name].pop(self.channel_name)
        if len(battlers[self.room_name])==0:
            battlers.pop(self.room_name)
            layouts.pop(self.room_name)
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type': 'end',
                    'data': []
                }
            )



    # Receive message from WebSocket
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)

        # Send message to room group
        if text_data_json['type']=='text':
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type': text_data_json['type'],
                    'data': text_data_json['data']
                }
            )
        elif text_data_json['type']=='position':
            available,end,points=handle(self.room_name,text_data_json['data'])
            if available:
                await self.channel_layer.group_send(
                    self.room_group_name,
                    {
                        'type':'layout',
                        'data':layouts[self.room_name]
                    }
                )
            if end:
                log=playerLog.objects.filter(email=text_data_json['email'])
                log.update(wins=log[0].wins+1)
                await self.channel_layer.group_send(
                    self.room_group_name,
                    {
                        'type':'end',
                        'data':points
                    }
                )
                battlers.pop(self.room_name)
                layouts.pop(self.room_name)
                self.close()

            
    async def end(self, event):
        await self.send(text_data=json.dumps({
            'type':'end',
            'data':event['data'],
        }))
        self.close()
        battlers.pop(self.room_name)
        layouts.pop(self.room_name)

    async def text(self, event):
        message = event['data']
        await self.send(text_data=json.dumps({
            'type':'text',
            'data': message
        }))

    async def layout(self,event):
        await self.send(text_data=json.dumps({
            'type':event['type'],
            'data':event['data']
        }))

class witnessConsumer(battleConsumer):
    async def connect(self):
        roomname = self.scope['url_route']['kwargs']['roomID']
        
        self.room_name = roomname
        self.room_group_name = 'gobang_%s' % self.room_name

        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        await self.accept()

    async def receive(self, text_data):
        text_data_json = json.loads(text_data)

        # Send message to room group
        if text_data_json['type']=='text':
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type': text_data_json['type'],
                    'data': text_data_json['data']
                }
            )


def handle(roomID,position):
    x=position[0]
    y=position[1]
    chess=position[2]
    available=False
    end=False
    points=None
    if layouts[roomID][x][y]==0:
        layouts[roomID][x][y]=chess
        available=True
    end,points=win(layouts[roomID],x,y,chess)
    return available,end,points

def win(layout,x,y,chess):
    win=False
    winDir=0
    points=[]
    direction=[
        [1,1],[-1,-1],
        [-1,1],[1,-1],
        [1,0],[-1,0],
        [0,1],[0,-1]
        ]
    counts=[0,0,0,0,0,0,0,0]
    for i in range(8):
        for j in range(1,5):
            if 0<=x+direction[i][0]*j and x+direction[i][0]*j<len(layout)  or 0<=y+direction[i][1]*j and y+direction[i][1]*j<len(layout[0]):
                if layout[x+direction[i][0]*j][y+direction[i][1]*j]==chess:
                    counts[i]+=1
                else:
                    break
            else:
                break
    for i in range(4):
        if counts[i*2]+counts[i*2+1]>=4:
            win=True
            winDir=int(i/2)*2
            break
    if win:
        for i in range(1,5):
            if 0<=x+direction[winDir][0]*i and x+direction[winDir][0]*i<len(layout)  or 0<=y+direction[winDir][1]*i and y+direction[winDir][1]*i<len(layout[0]):
                if layout[x+direction[winDir][0]*i][y+direction[winDir][1]*i]==chess:
                    points.append([x+direction[winDir][0]*i,y+direction[winDir][1]*i])
                else:
                    break
            else:
                break
        winDir+=1
        for i in range(1,5):
            if(len(points)==4):
                break
            if 0<=x+direction[winDir][0]*i and x+direction[winDir][0]*i<len(layout)  or 0<=y+direction[winDir][1]*i and y+direction[winDir][1]*i<len(layout[0]):
                if layout[x+direction[winDir][0]*i][y+direction[winDir][1]*i]==chess:
                    points.append([x+direction[winDir][0]*i,y+direction[winDir][1]*i])
                else:
                    break
            else:
                break
        points.append([x,y])
    return win,points